<?php

namespace api\controllers;

use api\controllers\base\BaseController;
use api\models\ActiveGoodForm;
use api\models\OrderForm;
use common\models\Order;

class BuyController extends BaseController
{

    /**
     *TODO 动作串联
     * TODO nginx配置 & 有优化策略
     *http://api.spike.com/?r=buy/buy
     */
    public function actionBuy()
    {
        $order_form = new OrderForm();
        $ret2check = $order_form->checkQueue2buy( \Yii::$app->user->id );

        if( !$ret2check[ 'status' ] ){
            return $this->response2Json( $ret2check[ 'status' ], $ret2check[ 'msg' ] );
        }

        $req_param = \Yii::$app->request->post();
        $login_userinfo = [
            'uid' => \Yii::$app->user->id,
            'username' => \Yii::$app->user->identity->username,
        ];

        // 参数的处理
        $active_id = $req_param[ 'active_id' ];
        $goods_id = $req_param[ 'goods_id' ];
        $goods_num = $req_param[ 'goods_num'];
        $sign_data = $req_param['user_sign'];
        $question_sign = $req_param['question_sign'];
        $ask = $req_param['ask'];
        $answer = $req_param['answer'];
        $action = isset($req_param['action']) ? $req_param['action'] : false;

        $now = time();
        $order_form = new OrderForm();
        $goods_model = new ActiveGoodForm();

        if ('buy_cart' == $action) {
            $goods_num = $_POST['num'][0];
        }
        $client_ip = $order_form->getClientIp();

        // TODO 验证用户是否登录
        if (!$login_userinfo || !$login_userinfo['uid']) {
            return $this->response2Json( false, '用户登录之后才可以参与', 101 );
        }
        $uid = $login_userinfo['uid'];
        $username = $login_userinfo['username'];

        // 2 验证参数是否正确、合法
        if (!$active_id || !$goods_id
            || !$goods_num || !$question_sign
        ) {
            $result = array('error_no' => '102', 'error_msg' => '参数提交异常');
            return $this->response2Json( false, '参数提交异常', 102 );
        }

        // 3.1 验证活动状态信息
        $status_check = false;
        $sign_data_info = $order_form->rc_encrypt( $sign_data,'D' );

        // 时间不能超过当前时间5分钟，IP和用户保持不变
        if ($sign_data_info
            && $sign_data_info['now'] < $now
            && $sign_data_info['now'] > $now - 300
            && $sign_data_info['ip'] == $client_ip
            && $sign_data_info['uid'] == $uid
        ) {
            $status_check = true;
        }
        if (!$status_check) {
            return $this->response2Json( false, '用户校验值验证没有通过', 103 );
        }


        // 3.2 验证问答信息是否正确
        $question_check = false;
        $question_info = $order_form->rc_encrypt( $question_sign,'D' );

        if ($question_sign && $question_info) {
            if ($question_info['ask'] == $ask
                && $question_info['answer'] == $answer
                && $question_info['aid'] == $active_id
                && $question_info['uid'] == $uid
                && $question_info['ip'] == $client_ip
                && $question_info['now'] > $now -300
            ) {
                $question_check = true;
            }
        }
        if (!$question_check) {
            return $this->response2Json( false, '问答验证没有通过', 103 );
        }

        // 统一格式化单商品、组合商品的数据结构
        $nums = $goods = array();
        if ('buy_cart' != $action) {
            $nums = array($goods_num);
            $goods = array($goods_id);
        } else {
            $num = $_POST['num'];
            $goods = $_POST['goods'];
        }


        foreach ($goods as $i => $goods_id) {
            $goods_list[] = 'info_g_' . $goods_id;  // 商品详情
        }
        $data_list = \Yii::$app->redis->mget( 'u_trade_' . $uid . '_' . $active_id,'st_a_' . $active_id );
        $good_data_list[] = \Yii::$app->redis->hgetall( $goods_list[ 0 ] );

        // 4 验证用户是否已经购买
        if ($data_list[0]) {
            $result = array('error_no' => '104', 'error_msg' => '请不要重复提交订单');
            return $this->response2Json( false, '请不要重复提交订单', 104 );
        }

        // 5 验证活动信息，商品信息是否正常
        if (!$data_list[1]) {
            return $this->response2Json( false, '活动信息异常', 105 );
        }
        unset($data_list[0]);
        unset($data_list[1]);

        // TODO 商品扣除
        $num_total = $price_total = $price_discount = 0;
        $trade_goods = array();
        foreach ($good_data_list as $i => &$goods_info) {
            $goods_info_tem = array_chunk( $goods_info, 2 );
            $goods_info = array_combine(
                array_column( $goods_info_tem,0 ),
                array_column( $goods_info_tem,1 )
            );

            $goods_num = $nums[ 0 ];

            // $goods_info = $goods_model->get($goods_id);
            if (!$goods_info || $goods_info['sys_status'] !== '1') {
                return $this->response2Json( false, '商品信息异常', 106 );
            }

            // 6 验证用户购买的商品数量是否在限制的范围内
            if ($goods_num > $goods_info['num_user']) {
                return $this->response2Json( false, '超出商品数量的限制', 107 );
            }

            // 7 验证商品是否还有剩余数量
            if ($goods_info['num_left'] < $goods_num) {
                return $this->response2Json( false, '商品剩余数量不足', 108 );
            }

            // 8 扣除商品剩余数量

            // 注意并发编程,使用自增自减 而非 直接设置操作,避免产生脏数据
            // 注重细节的思考,容易出现瑕疵,瑕疵在并发下会被无限放大
            $left = $goods_model->changeLeftNumCached($goods_id, 0-$goods_num);
            $ok = false;
            if ($left >= 0) {
                $ok = $goods_model->changeLeftNum($goods_id, 0-$goods_num);
            } else {
                // 扣除商品库存失败
                $goods_model->changeStatusCached($goods_id, 0);

                //生成抢购完的js静态文件 抵御请求
                file_put_contents(ROOT_PATH . '/web/astatus/' . $active_id . '_' . $goods_id . '.js', '{"error_no":"202","error_msg":"\u6d3b\u52a8\u5546\u54c1\u5df2\u4e0b\u67b6\u6216\u8005\u5df2\u552e\u5b8c"}');

                return $this->response2Json( false, '商品剩余数量不足', 108 );
            }


            // 9.1 创建订单信息，订单的商品信息
            $trade_goods[] = array(
                'goods_info' => $goods_info,
                'goods_num' => $goods_num
            );
            $num_total += $goods_num;
            $price_total += $goods_info['price_normal'] * $goods_num;
            $price_discount += $goods_info['price_discount'] * $goods_num;
        }

        // 9.2 保存订单信息
        $trade_model = new Order();
        $trade_info = array(
            'active_id' => $active_id,
            'goods_id' => $goods_id,
            'num_total' => $num_total,
            'num_goods' => count($goods),
            'price_total' => $price_total,
            'price_discount' => $price_discount,
            'goods_info' => json_encode($trade_goods),
            'uid' => $uid,
            'username' => $username,
            'sys_ip' => $client_ip,
            'sys_dateline' => $now,
            'time_confirm' => $now,
            'sys_status' => 1,
        );

        foreach ($trade_info as $k => $v) {
            $trade_model->$k = $v;
        }

        $trade_id = $trade_model->save();
        if ($trade_id) {
            // 用户已经购买，状态放到缓存中
            \Yii::$app->redis->set( 'u_trade_' . $uid . '_' . $active_id, 1 );
        }

        // 10 返回提示信息
        return $result = '秒杀成功，请尽快去支付';
    }
}
